import struct
import time
import threading
import os
from enum import Enum
from typing import Dict, List, Optional, Tuple, Any, Set
from .disk_manager import DiskManager
from utils.serializer import Serializer

class RedoLogType(Enum):
    """日志类型枚举"""
    BEGIN = 1    # 事务开始
    COMMIT = 2   # 事务提交
    ABORT = 3    # 事务中止
    INSERT = 4   # 插入记录
    DELETE = 5   # 删除记录
    UPDATE = 6   # 更新记录
    CHECKPOINT = 7  # 检查点

class BinLogType(Enum):
    """二进制日志类型枚举"""
    STATEMENT = 1  # SQL语句
    ROW = 2       # 行变更

class SimpleLogger:
    """简单日志记录器
    
    提供基本的日志文件读写功能
    """
    
    def __init__(self, log_path: str):
        """初始化简单日志记录器
        
        Args:
            log_path: 日志文件路径（不含扩展名）
        """
        self.log_path = log_path + ".log"
        self.file = None
        self.position = 0
        self.lock = threading.RLock()
    
    def create(self) -> None:
        """创建新的日志文件"""
        with self.lock:
            # 确保目录存在
            os.makedirs(os.path.dirname(os.path.abspath(self.log_path)), exist_ok=True)
            
            # 创建新文件
            self.file = open(self.log_path, 'w+b')
            # 写入文件头（校验和占位符）
            self.file.write(struct.pack('<I', 0))  # 初始校验和
            self.file.flush()
            self.position = 4
    
    def open(self) -> None:
        """打开已存在的日志文件"""
        with self.lock:
            if not os.path.exists(self.log_path):
                raise FileNotFoundError(f"Log file not found: {self.log_path}")
            
            self.file = open(self.log_path, 'r+b')
            # 定位到文件末尾
            self.file.seek(0, os.SEEK_END)
            self.position = self.file.tell()
    
    def log(self, data: bytes) -> None:
        """写入日志数据
        
        Args:
            data: 要写入的日志数据
        """
        with self.lock:
            if not self.file:
                raise RuntimeError("Logger not initialized")
            
            # 计算数据长度
            data_len = len(data)
            
            # 写入数据长度和数据
            log_entry = struct.pack('<I', data_len) + data
            
            # 定位到文件末尾并写入
            self.file.seek(0, os.SEEK_END)
            self.file.write(log_entry)
            self.file.flush()
            
            self.position = self.file.tell()
    
    def next(self) -> Optional[bytes]:
        """读取下一条日志记录
        
        Returns:
            日志数据，如果没有更多记录则返回None
        """
        with self.lock:
            if not self.file:
                return None
            
            # 读取数据长度
            len_data = self.file.read(4)
            if len(len_data) != 4:
                return None
            
            data_len = struct.unpack('<I', len_data)[0]
            
            # 读取实际数据
            data = self.file.read(data_len)
            if len(data) != data_len:
                return None
            
            return data
    
    def rewind(self) -> None:
        """重置读取位置到文件开始"""
        with self.lock:
            if self.file:
                self.file.seek(4)  # 跳过文件头
    
    def close(self) -> None:
        """关闭日志文件"""
        with self.lock:
            if self.file:
                self.file.close()
                self.file = None

class BinLogger:
    """二进制日志管理器

    记录数据库的逻辑变更，用于复制和时间点恢复
    """

    BIN_LOG_SUFFIX = ".binlog"

    def __init__(self, disk_manager: DiskManager):
        """初始化二进制日志管理器

        Args:
            disk_manager: 磁盘管理器
        """
        self.disk_manager = disk_manager

        # 获取数据库文件路径的目录
        if hasattr(disk_manager, 'db_file_path'):
            base_path = os.path.dirname(disk_manager.db_file_path)
        else:
            base_path = os.path.dirname(str(disk_manager))

        # 初始化binlog文件
        binlog_path = os.path.join(base_path, "binlog")
        self.bin_logger = SimpleLogger(binlog_path)

        try:
            self.bin_logger.open()
        except:
            self.bin_logger.create()

        self.lock = threading.RLock()

    def log_statement(self, txn_id: int, sql: str) -> None:
        """记录SQL语句

        Args:
            txn_id: 事务ID
            sql: SQL语句
        """
        with self.lock:
            # 序列化SQL语句
            data = struct.pack("<I", BinLogType.STATEMENT.value)
            data += struct.pack("<I", txn_id)
            data += struct.pack("<I", len(sql))
            data += sql.encode('utf-8')

            self.bin_logger.log(data)

    def log_row(self, txn_id: int, table_name: str, operation: str, row_data: bytes) -> None:
        """记录行变更

        Args:
            txn_id: 事务ID
            table_name: 表名
            operation: 操作类型（INSERT/UPDATE/DELETE）
            row_data: 行数据
        """
        with self.lock:
            # 序列化行变更
            data = struct.pack("<I", BinLogType.ROW.value)
            data += struct.pack("<I", txn_id)
            data += struct.pack("<I", len(table_name))
            data += table_name.encode('utf-8')
            data += struct.pack("<I", len(operation))
            data += operation.encode('utf-8')
            data += struct.pack("<I", len(row_data))
            data += row_data

            self.bin_logger.log(data)

    def close(self) -> None:
        """关闭二进制日志"""
        if self.bin_logger:
            self.bin_logger.close()

class LogRecord:
    """简化的日志记录
    
    使用 serializer.py 的统一序列化功能
    """
    
    # 定义日志记录的结构化Schema
    LOG_SCHEMA = [
        ('txn_id', 'uint32'),
        ('log_type', 'uint32'), 
        ('timestamp', 'uint64'),
        ('page_id', 'int32'),
        ('offset', 'int32'),
        ('data_len', 'uint32')
    ]
    
    def __init__(self, txn_id: int, log_type: RedoLogType, page_id: int = -1,
                 offset: int = -1, data: bytes = b""):
        """初始化日志记录
        
        Args:
            txn_id: 事务ID
            log_type: 日志类型
            page_id: 页面ID
            offset: 记录偏移量
            data: 数据内容
        """
        self.txn_id = txn_id
        self.log_type = log_type
        self.page_id = page_id
        self.offset = offset
        self.data = data
        self.timestamp = int(time.time() * 1000000)  # 微秒级时间戳
    
    def serialize(self) -> bytes:
        """将日志记录序列化为字节序列
        
        使用 Serializer 进行结构化序列化
        
        Returns:
            序列化后的字节序列
        """
        # 准备结构化数据
        record_data = {
            'txn_id': self.txn_id,
            'log_type': self.log_type.value,
            'timestamp': self.timestamp,
            'page_id': self.page_id,
            'offset': self.offset,
            'data_len': len(self.data)
        }
        
        # 使用序列化器
        serializer = Serializer(schema=self.LOG_SCHEMA)
        header = serializer.serialize_record(record_data)
        
        return header + self.data

    @classmethod
    def deserialize(cls, data: bytes) -> 'LogRecord':
        """从字节序列反序列化日志记录
        
        Args:
            data: 序列化的日志记录数据
            
        Returns:
            反序列化后的日志记录对象
        """
        # 创建序列化器
        serializer = Serializer(schema=cls.LOG_SCHEMA)
        
        # 计算头部大小
        header_size = struct.calcsize(serializer.format)
        
        # 反序列化头部
        header_data = serializer.deserialize_record(data[:header_size])
        
        # 提取字段
        txn_id = header_data['txn_id']
        log_type = RedoLogType(header_data['log_type'])
        timestamp = header_data['timestamp']
        page_id = header_data['page_id']
        offset = header_data['offset']
        data_len = header_data['data_len']
        
        # 提取数据部分
        record_data = data[header_size:header_size + data_len]
        
        # 创建日志记录对象
        log_record = cls(txn_id, log_type, page_id, offset, record_data)
        log_record.timestamp = timestamp
        
        return log_record

class RedoLogManager:
    """日志管理器（向后兼容）
    
    实现类似InnoDB的redo log功能
    """
    def __init__(self, disk_manager: DiskManager):
        """初始化日志管理器
        
        Args:
            disk_manager: 磁盘管理器
        """
        self.disk_manager = disk_manager
        
        # 获取数据库文件路径的目录
        if hasattr(disk_manager, 'db_file_path'):
            base_path = os.path.dirname(disk_manager.db_file_path)
        else:
            # 如果disk_manager是字符串路径（兼容旧代码）
            base_path = os.path.dirname(str(disk_manager))
        
        # 初始化redo日志
        redo_log_path = os.path.join(base_path, "redo")
        self.redo_logger = SimpleLogger(redo_log_path)
        
        # 尝试打开已存在的日志文件，如果不存在则创建
        try:
            self.redo_logger.open()
        except:
            self.redo_logger.create()
        
        # 事务管理
        self.active_transactions: Set[int] = set()
        self.lock = threading.RLock()
    
    def begin_transaction(self, txn_id: int) -> None:
        """开始事务"""
        with self.lock:
            log_record = LogRecord(txn_id, RedoLogType.BEGIN)
            self.redo_logger.log(log_record.serialize())
            self.active_transactions.add(txn_id)
    
    def commit_transaction(self, txn_id: int) -> None:
        """提交事务"""
        with self.lock:
            log_record = LogRecord(txn_id, RedoLogType.COMMIT)
            self.redo_logger.log(log_record.serialize())
            self.active_transactions.discard(txn_id)
    
    def abort_transaction(self, txn_id: int) -> None:
        """中止事务"""
        with self.lock:
            log_record = LogRecord(txn_id, RedoLogType.ABORT)
            self.redo_logger.log(log_record.serialize())
            self.active_transactions.discard(txn_id)
    
    def log_insert(self, txn_id: int, page_id: int, offset: int, data: bytes) -> None:
        """记录插入操作"""
        log_record = LogRecord(txn_id, RedoLogType.INSERT, page_id, offset, data)
        self.redo_logger.log(log_record.serialize())
    
    def log_delete(self, txn_id: int, page_id: int, offset: int, data: bytes) -> None:
        """记录删除操作"""
        log_record = LogRecord(txn_id, RedoLogType.DELETE, page_id, offset, data)
        self.redo_logger.log(log_record.serialize())
    
    def log_update(self, txn_id: int, page_id: int, offset: int, old_data: bytes, new_data: bytes) -> None:
        """记录更新操作"""
        # 记录旧数据用于undo
        log_record = LogRecord(txn_id, RedoLogType.UPDATE, page_id, offset, old_data + new_data)
        self.redo_logger.log(log_record.serialize())
    
    def checkpoint(self) -> None:
        """创建检查点"""
        with self.lock:
            # 简化的检查点实现
            checkpoint_data = struct.pack("<I", len(self.active_transactions))
            for txn_id in self.active_transactions:
                checkpoint_data += struct.pack("<I", txn_id)
            
            log_record = LogRecord(0, RedoLogType.CHECKPOINT, -1, -1, checkpoint_data)
            self.redo_logger.log(log_record.serialize())
    
    def close(self) -> None:
        """关闭日志管理器"""
        if self.redo_logger:
            self.redo_logger.close()
    
    # 向后兼容方法
    def append_log_record(self, log_record) -> int:
        """追加日志记录（向后兼容）"""
        # 简化实现，直接使用新的log_insert方法
        if hasattr(log_record, 'txn_id') and hasattr(log_record, 'after_data'):
            self.log_insert(log_record.txn_id, getattr(log_record, 'page_id', -1), 
                          getattr(log_record, 'offset', -1), log_record.after_data)
        return 1  # 返回一个虚拟LSN
    
    def flush_log(self) -> bool:
        """刷新日志（向后兼容）"""
        return True  # 我们的实现是同步的，总是返回True